package com.soc.auth.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.soc.auth.domain.dto.*;
import com.soc.auth.domain.entity.Class;
import com.soc.auth.domain.entity.CourseClass;
import com.soc.auth.domain.entity.Roster;
import com.soc.auth.domain.entity.TeacherClass;
import com.soc.auth.domain.vo.ClassMemberVO;
import com.soc.auth.domain.vo.ClassVO;
import com.soc.auth.domain.vo.PageVO;
import com.soc.auth.exception.BusinessException;
import com.soc.auth.mapper.ClassMapper;
import com.soc.auth.service.ClassService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.soc.auth.service.CourseClassService;
import com.soc.auth.service.RosterService;
import com.soc.auth.service.TeacherClassService;
import com.soc.auth.utils.CurrentUserUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author HongZhouAn
 * @since 2023-06-25
 */
@Service
@RequiredArgsConstructor
public class ClassServiceImpl extends ServiceImpl<ClassMapper, Class> implements ClassService {

    private final CourseClassService courseClassService;

    private final RosterService rosterService;

    private final TeacherClassService teacherClassService;

    /**
     * 创建班级
     * @param classCreateDTO 创建班级所需要的信息
     * @return 班级绑定码
     */
    @Transactional
    @Override
    public ClassVO createClass(ClassCreateDTO classCreateDTO) {

        if (ObjectUtil.isNotNull(this.getOne(new LambdaQueryWrapper<Class>()
                .eq(Class::getName, classCreateDTO.getName())))) {
            throw new BusinessException("班级已存在");
        }

        // 将班级信息存入到数据库中
        Class c = new Class();
        c.setName(classCreateDTO.getName());
        c.setCreatorId(CurrentUserUtil.getCurrentUser().getId());
        c.setSchoolId(CurrentUserUtil.getCurrentUser().getSchoolId());
        c.setCreateTime(new Date());
        // 生成邀请码
        c.setBindCode(RandomUtil.randomString(6));
        if (!this.save(c)) {
            throw new RuntimeException("系统出现错误");
        }

        // 将班级id存入到t_course_class中间表中，相当于把该班级绑定到课程中
        CourseClass courseClass = new CourseClass();
        courseClass.setCourseId(classCreateDTO.getCourseId());
        courseClass.setClassId(c.getId());
        if (!courseClassService.save(courseClass)) {
            throw new RuntimeException("系统出现错误");
        }

        // 将班级id存入到t_teacher_class中间表中
        TeacherClass teacherClass = new TeacherClass();
        teacherClass.setTeacherId(CurrentUserUtil.getCurrentUser().getId());
        teacherClass.setClassId(c.getId());
        if (!teacherClassService.save(teacherClass)) {
            throw new RuntimeException("系统出现错误");
        }

        return BeanUtil.toBean(c, ClassVO.class);
    }

    /**
     * 批量导入学生加入班级
     */
    @Transactional
    @Override
    public boolean joinClassBatch(JoinClassDTO joinClassDTO) {

        // 请求数据是否合法的标记
        boolean isIllegal = false;

        List<StudentForm> studentFormList = joinClassDTO.getStudentFormList();

        // 将学号和姓名字段 joint 在一起, 用来判断是否存在重复
        Set<String> studentsJointInfo = new HashSet<>(studentFormList.size());
        // 过滤出来的, 可以保存在数据库的学生信息(规则按照自己的业务需求自定义即可)
        List<StudentForm> filteredStudentsInfo = new ArrayList<>(studentFormList.size());

        for (StudentForm studentForm : studentFormList) {
            if (studentsJointInfo.contains(studentForm.getNo())) {
                // no存在于studentsJointInfo容器中，则表示信息重复
                isIllegal = true;
            }

            // 加入到两个容器中
            studentsJointInfo.add(String.valueOf(studentForm.getNo())); //goodsJointInfos是Set类型的集合
            filteredStudentsInfo.add(studentForm);
        }

        // 如果所传参数存在重复学生的学号或者是没有需要导入的学生, 直接打印日志返回
        if (isIllegal || CollectionUtil.isEmpty(filteredStudentsInfo)) {
            log.error("批量导入学生时所传数据的学号存在重复或者所传数据为空");
            throw new BusinessException("批量导入学生时所传数据的学号存在重复或者所传数据为空");
        }

        List<Roster> rosterList = BeanUtil.copyToList(filteredStudentsInfo, Roster.class);

        AtomicInteger peopleNumber = new AtomicInteger();
        rosterList.forEach(roster -> {
            if (null != rosterService.getOne(new LambdaQueryWrapper<Roster>()
                    .eq(Roster::getNo, roster.getNo())
            )) {
                throw new BusinessException("已经导入过该学生信息，学号为：" + roster.getNo());
            }
            peopleNumber.getAndIncrement();
            roster.setClassId(joinClassDTO.getClassId());
        });
        boolean result1 = this.update(new LambdaUpdateWrapper<Class>()
                .set(Class::getPeopleNumber, peopleNumber.get())
                .eq(Class::getId, joinClassDTO.getClassId())
        );
        if (!result1) {
            throw new BusinessException("更新班级人数的数据失败");
        }

        boolean result2 = rosterService.saveBatch(rosterList);
        if (!result2) {
            throw new BusinessException("批量导入学生名单进入数据库的操作失败");
        }

        return true;

    }

    /**
     * 查询指定学校下的班级
     */
    @Override
    public PageVO<ClassVO> listClassPagesBySchoolId(ClassSchoolPageQuery queryParams, String schoolId) {

        LambdaQueryWrapper<Class> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Class::getSchoolId, schoolId);
        Page<Class> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        this.page(page, lambdaQueryWrapper);

        List<Class> classList = page.getRecords();
        List<ClassVO> classVOList = BeanUtil.copyToList(classList, ClassVO.class);
        return new PageVO<>(classVOList, page.getTotal());
    }

    /**
     * 查询当前老师所创建的班级
     */
    @Override
    public PageVO<ClassVO> listClassPages(ClassTeacherPageQuery queryParams) {

        LambdaQueryWrapper<Class> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StrUtil.isNotBlank(queryParams.getName()), Class::getName, queryParams.getName());
        lambdaQueryWrapper.eq(Class::getCreatorId, queryParams.getCreatorId());
        Page<Class> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        this.page(page, lambdaQueryWrapper);

        List<Class> classList = page.getRecords();
        List<ClassVO> classVOList = BeanUtil.copyToList(classList, ClassVO.class);
        return new PageVO<>(classVOList, page.getTotal());
    }

    @Override
    public PageVO<ClassMemberVO> listClassMemberPages(ClassMemberPageQuery queryParams) {

        LambdaQueryWrapper<Roster> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StrUtil.isNotBlank(queryParams.getNo()), Roster::getNo, queryParams.getNo());
        lambdaQueryWrapper.like(StrUtil.isNotBlank(queryParams.getRealName()), Roster::getRealName, queryParams.getRealName());
        lambdaQueryWrapper.eq(Roster::getClassId, queryParams.getClassId());
        Page<Roster> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        rosterService.page(page, lambdaQueryWrapper);

        List<Roster> rosterList = page.getRecords();
        List<ClassMemberVO> classMemberVOList = BeanUtil.copyToList(rosterList, ClassMemberVO.class);
        return new PageVO<>(classMemberVOList, page.getTotal());

    }

    /**
     * 将不是老师自己创建的班级绑定到指定课程
     */
    @Override
    @Transactional
    public boolean bindCourse(ClassBindDTO classBindDTO) {

        if (ObjectUtil.isNull(courseClassService.getOne(new LambdaUpdateWrapper<CourseClass>()
                .eq(CourseClass::getCourseId, classBindDTO.getCourseId())
                .eq(CourseClass::getClassId, classBindDTO.getClassId())))) {
            // t_course_class中间表中不存在该数据，才能存储数据到数据库
            // 将班级id存入到t_course_class中间表中，相当于把该班级绑定到课程中
            CourseClass courseClass = new CourseClass();
            courseClass.setCourseId(classBindDTO.getCourseId());
            courseClass.setClassId(classBindDTO.getClassId());
            if (!courseClassService.save(courseClass)) {
                throw new RuntimeException("系统出现异常");
            }
        }

        // 将班级id存入到t_teacher_class中间表中，表明让该班级被该老师使用
        // 先去校验t_teacher_class中间表中是否存在该数据
        String userId = CurrentUserUtil.getCurrentUser().getId();
        if (ObjectUtil.isNull(teacherClassService.getOne(new LambdaUpdateWrapper<TeacherClass>()
                .eq(TeacherClass::getTeacherId, userId)
                .eq(TeacherClass::getClassId, classBindDTO.getClassId())))) {
            // t_teacher_class中间表中不存在该数据，才能存储数据到数据库
            // 将班级id存入到t_teacher_class中间表中
            TeacherClass teacherClass = new TeacherClass();
            teacherClass.setTeacherId(userId);
            teacherClass.setClassId(classBindDTO.getClassId());
            if (!teacherClassService.save(teacherClass)) {
                throw new RuntimeException("系统出现异常");
            }
        }

        return true;
    }

    /**
     * 查询指定课程下当前老师所管理的所有班级
     */
    @Override
    public PageVO<ClassVO> listClassPagesByCourseId(ClassCoursePageQuery queryParams, String teacherId) {
        // 获得当前老师的用户id
        queryParams.setTeacherId(CurrentUserUtil.getCurrentUser().getId());

        // 根据当前老师的用户id和课程id获得班级
        Page<Class> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
        List<Class> classList = this.baseMapper.listClassPagesByCourseIdAndTeacherId(page, queryParams, teacherId);

        List<ClassVO> classVOList = BeanUtil.copyToList(classList, ClassVO.class);
        return new PageVO<>(classVOList, page.getTotal());
    }

    /**
     * 修改班级名称
     */
    @Override
    public boolean updateClassInfo(ClassUpdateDTO classUpdateDTO) {

        return this.update(new LambdaUpdateWrapper<Class>()
                .set(Class::getName, classUpdateDTO.getName())
                .eq(Class::getId, classUpdateDTO.getClassId())
        );
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeClassByIds(List<String> classIds) {

        List<String> removeIds = new ArrayList<>();

        // 在t_course_class表中将所有要删除的班级对应的id都获得出来
        for (String classId : classIds) {
            List<CourseClass> list = courseClassService.list(new LambdaQueryWrapper<CourseClass>()
                    .select(CourseClass::getId)
                    .eq(CourseClass::getClassId, classId)
            );
            List<String> longs = list.stream().map(CourseClass::getId).collect(Collectors.toList());
            removeIds.addAll(longs);
        }

        // 删除课程与班级的中间表t_course_class中的数据
        boolean result1 = courseClassService.removeByIds(removeIds);
        if (!result1) {
            throw new BusinessException("删除操作出现错误");
        }

        boolean result2 = this.removeByIds(classIds);
        if (!result2) {
            throw new BusinessException("删除操作出现错误");
        }

        return true;
    }
}
